import math
from dataclasses import dataclass
from typing import Any, Union

from sqlalchemy import text, func, Select

from app.core.dependencies import SessionDep


@dataclass
class Pagination:
    page_num: int
    page_size: int
    total: int
    pages: int
    data: Union[list, None]
    # def __init__(self, page_num: int, page_size: int, total: int, pages: int, data: Union[list, None]):
    #     self.page_num = page_num
    #     self.page_size = page_size
    #     self.total = total
    #     self.pages = pages
    #     self.data = data


def page_query(session: SessionDep, *, statement: Union[Select[Any]], page_num: int = 1,
               page_size: int = 10, cls: Any = None) -> Pagination:
    count_statement = statement.with_only_columns(func.count())
    total_count = session.execute(count_statement.offset(page_size * (page_num - 1)).limit(page_size)).fetchone()[0]
    result = session.execute(statement).scalars().all()
    if cls:
        result = [cls(**item.to_dict()) for item in result]
    return Pagination(
        page_num=page_num,
        page_size=page_size,
        total=total_count,
        pages=math.ceil(total_count / page_size),
        data=result
    )


def page_query_by_sql(session: SessionDep, *, query_sql: str, page_num: int = 1, page_size: int = 10,
                      params: dict = None, cls: Any = None) -> Pagination:
    count_sql = f"select count(*) from ({query_sql}) t"
    total_count = session.execute(text(count_sql).bindparams(**(params if params else {}))).fetchone()[0]  # 元祖
    total_count = int(total_count)
    results: dict = session.execute(text(f"{query_sql} limit {page_size * (page_num - 1)},{page_size}").bindparams(
        **params)).mappings().fetchall()  # 字典
    data = [cls(**item) for item in results] if cls else results
    return Pagination(
        page_num=page_num,
        page_size=page_size,
        total=total_count,
        pages=math.ceil(total_count / page_size),
        data=data
    )
